package utils

import (
	"encoding/json"
	"fmt"
	"math"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/cover"
)

type TreeNode struct {
	Name           string      `json:"name"`
	Type           string      `json:"type"`
	Children       []*TreeNode `json:"children,omitempty"`
	IsTracked      bool        `json:"is_tracked"`
	CoveredPercent float64     `json:"cover_percent"`
}

func isTracked(profile *cover.Profile) bool {
	for _, value := range profile.Blocks {
		if value.NumStmt > 0 {
			return true
		}
	}
	return false
}

func coverPercent(profile *cover.Profile) float64 {
	var total, cover int
	for _, value := range profile.Blocks {
		total += value.NumStmt

		if value.Count > 0 {
			cover += value.NumStmt
		}
	}
	if total == 0 {
		return 0.0
	}
	return float64(cover / total)
}

func GenerateTree(absCodePath string, moduleName string) (*TreeNode, error) {
	if !filepath.IsAbs(absCodePath) {
		return nil, fmt.Errorf("需要绝对路径: %s", absCodePath)
	}

	profiles, err := cover.ParseProfiles(filepath.Join(absCodePath, "coverage.out"))
	if err != nil {
		return nil, err
	}
	fmt.Printf("tree profile:%v\n", profiles)

	info, err := os.Lstat(absCodePath)
	if err != nil {
		return nil, err
	}

	root := &TreeNode{
		Name: info.Name(),
		Type: "directory",
	}
	for _, file := range profiles {

		filePath := filepath.Clean(file.FileName)
		filePath = strings.TrimPrefix(filePath, moduleName+"/")
		components := strings.Split(filePath, string(filepath.Separator))
		currentNode := root
		for i := 0; i < len(components)-1; i++ {
			component := components[i]
			var foundNode *TreeNode
			for _, child := range currentNode.Children {
				if child.Name == component && child.Type == "directory" {
					foundNode = child
					break
				}
			}
			if foundNode == nil {
				foundNode = &TreeNode{
					Name: component,
					Type: "directory",
				}
				currentNode.Children = append(currentNode.Children, foundNode)
			}
			currentNode = foundNode
		}
		fileName := components[len(components)-1]
		fileNode := &TreeNode{
			Name: fileName,
			Type: "file",
		}

		total, covered := computeCoverage(file)
		if total > 0 {
			fileNode.IsTracked = true
			fileNode.CoveredPercent = (float64(covered) / float64(total)) * 100
		} else {
			fileNode.IsTracked = false
			fileNode.CoveredPercent = 0
		}

		currentNode.Children = append(currentNode.Children, fileNode)
	}

	fmt.Println("gene")
	processDirectory(root)
	return root, nil
}
func processDirectory(node *TreeNode) {
	if node.Type != "directory" {
		return
	}
	minPercent := math.MaxFloat64
	hasTracked := false
	for _, child := range node.Children {
		if child.Type == "directory" {
			processDirectory(child)
		}
		if child.IsTracked {
			hasTracked = true
			if child.CoveredPercent < minPercent {
				minPercent = child.CoveredPercent
			}
		}
	}
	node.IsTracked = hasTracked
	if hasTracked {
		node.CoveredPercent = minPercent
	} else {
		node.CoveredPercent = 0
	}
	// 对 children 进行排序
	sort.Slice(node.Children, func(i, j int) bool {
		if node.Children[i].Type == "directory" && node.Children[j].Type == "file" {
			return true
		}
		if node.Children[i].Type == "file" && node.Children[j].Type == "directory" {
			return false
		}
		return node.Children[i].Name < node.Children[j].Name
	})
}
func Tree(absCodePath string, moduleName string) (string, error) {
	root, err := GenerateTree(absCodePath, moduleName)
	if err != nil {
		return "", err
	}
	jsonData, _ := json.MarshalIndent(root, " ", " ")
	fmt.Printf("dirjson%s", jsonData)
	return string(jsonData), nil

}
func computeCoverage(profile *cover.Profile) (total int, covered int) {

	for _, block := range profile.Blocks {
		total += block.NumStmt
		if block.Count > 0 {
			covered += block.NumStmt
		}
	}

	return total, covered
}
